# -*- coding: utf-8 -*-
# standard
import os
import sys
import json
from datetime import datetime
from datetime import timedelta

# third
import requests

# local
_P_PATH =  os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if _P_PATH not in sys.path:
    sys.path.append(_P_PATH)
from toolbox.common_tools import R_P_PATH
from toolbox.common_tools import logger
from models import *


"""
@Title:   天勍的接口
@File: tianqing_func.py
@Author: walle 2024年11日06日 14时41分58秒
@Version: 1.0.0
@Desc: 
"""



TIANQING_LOGIN_INFO = {"user_id": "", "token": "", "expiry_time": None}  # 天勍的登录信息
TIANQING_SENSORS_CACHE_KEY = "tianqing-sensors"  # 天勍传感器的缓存key
TIANQING_SENSORS_CACHE_SSL = 3600  # 天勍传感器缓存的生存时间


def tianqing_send_request(method: str, url: str, **kwargs) -> Resp:
    """
    天勍的发送请求
    """
    resp = Resp()
    if method.lower() == "get":
        handler = requests.get
    else:
        handler = requests.post
    
    if "headers" not in kwargs:
        resp = tianqing_get_headers()
        if resp:
            headers = resp.data
            kwargs['headers'] = headers
        else:
            pass
    if resp:
        response = None
        try:
            response = handler(url=url, **kwargs)
        except Exception as e:
            logger.error(e)
            resp.message = f"向天勍后台发送请求出错:{e}"
        finally:
            if resp:
                if response.status_code != 200:
                    resp.message = f"服务端返回了错误的状态码:{response.status_code}"
                else:
                    data = response.json()
                    if (status := data['status']) != 0:
                        resp.message = f"服务端应用返回了错误的状态: status: {status}, code: {data['code']}, msg: {data['msg']}"
                    else:
                        resp.data = data['data']
            else:  # 无需处理
                ...
    else: # 无需处理
        pass
    return resp
    

def tianqing_login() -> Resp:
    """
    上海天勍的登录
    """
    url = "https://xcx.itianqing.com/scat-api/auth/login"
    json_data = {
        "name": "24110117225300051",  # 用户名
        "password": "yhkj666888",  # 密码
        "companyId": "",  # 企业id
    }
    resp = tianqing_send_request(method="post", url=url, json=json_data, headers={})
    if resp:
        expiry_time = datetime.now() + timedelta(seconds=(resp.data['failureTime'] - 60))
        expiry_time = expiry_time.strftime("%Y-%m-%d %H:%M:%S")
        TIANQING_LOGIN_INFO['user_id'] = resp.data['userId']
        TIANQING_LOGIN_INFO['token'] = resp.data['token']
        TIANQING_LOGIN_INFO['expiry_time'] = expiry_time
        # 保存到文件中
        file_path = os.path.join(R_P_PATH, "configure", "tianqing_key.json")
        with open(file=file_path, mode="w", encoding="utf-8") as f:
            json.dump(TIANQING_LOGIN_INFO, fp=f, ensure_ascii=False, indent=4)
        resp = Resp(data=resp.data['token'])
    else:
        pass
    return resp


def tianqing_get_token():
    """
    天勍获取token
    """
    expiry_time = TIANQING_LOGIN_INFO['expiry_time']
    if expiry_time is None:
        # 从文件中读取
        file_path = os.path.join(R_P_PATH, "configure", "tianqing_key.json")
        if not os.path.exists(file_path):
            with open(file=file_path, mode="w", encoding="utf-8") as f:
                json.dump(obj=TIANQING_LOGIN_INFO,fp=f)
        with open(file=file_path, mode="r", encoding="utf-8") as f:
            try:
                data = json.load(fp=f)
            except:
                data = {}
        TIANQING_LOGIN_INFO.update(data)
        expiry_time = TIANQING_LOGIN_INFO.get("expiry_time")
        if expiry_time is None:
            flag = False
        else:
            t = datetime.strptime(expiry_time, "%Y-%m-%d %H:%M:%S")
            TIANQING_LOGIN_INFO['expiry_time'] = expiry_time
            flag = (datetime.now() - t).total_seconds() < 0
    else:
        t = datetime.strptime(expiry_time, "%Y-%m-%d %H:%M:%S")
        flag = (datetime.now() - t).total_seconds() < 0
   
    if not flag: # 需要重新初始化
        resp = tianqing_login()
    else:

        resp = Resp(data=TIANQING_LOGIN_INFO['token'])
    return resp
    

def tianqing_get_headers() -> Resp:
    """
    获取天勍的请求头
    """
    resp = tianqing_get_token()
    if resp:
        resp.data = {"Authorization": resp.data}
    return resp


def tianqing_get_customers() -> Resp:
    """
    获取天勍的商户列表
    """
    url = "https://xcx.itianqing.com/scat-api/v1/wms/data/getMerchantList"
    params = {
        "limit": 100,
        "offset": 0,
    }
    resp = tianqing_send_request(method="get", url=url, params=params)
    return resp


def tianqing_get_merchant_selector() -> Resp:
    """
    获取天勍的商户列表
    """
    resp = tianqing_get_customers()
    if resp:
        resp.data = [{
            "value": x['merchantId'],
            "name": x['merchantName']
        } for x in resp.data['records']]
    return resp


def tianqing_get_store_selector(merchant_no: str) -> Resp:
    """
    获取天勍的商户列表
    """
    resp = tianqing_get_stores(merchant_no)
    if resp:
        resp.data = [{
            "value": x['storeId'],
            "name": x['storeName']
        } for x in resp.data['records']]
    return resp


def tianqing_get_stores(merchant_no: str) -> Resp:
    """
    获取天勍的商户列表
    'merchantId' = 'jiyoujia'
    """
    url = "https://xcx.itianqing.com/scat-api/v1/wms/data/getStoreList"
    params = {
        "limit": 100,
        "offset": 0,
        "merchantId": merchant_no,
    }
    resp = tianqing_send_request(method="get", url=url, params=params)
    return resp


def tianqing_package_raw_sensor_to_standard(sensor_category: str,
                                            merchant_no: str,
                                            customer_id: int, 
                                            store_id: int, data: dict) -> dict:
    """
    将天勍的原始传感器信息封装成标准格式
    """
    return {
        "sensor_category": sensor_category,
        "merchant_no": merchant_no,
        "customer_id": customer_id,
        "manufacturer": TemperatureSensorManufacturer.TIAN_QING.value,  # 无论电量还是温度传感器，厂家都是天勍
        "store_id": store_id,
        "uuid": data['hostNo'],
        "group_id": 1,
        "sensor_sn": data['sensorId'],
        "alias": data['name'],
        "desc": data['name'],
    }


def tianqing_get_sensor_selector(customer_id: int, store_id: int, 
                                 sensor_category: str, merchant_no: str,
                                 store_no: str, ignore_related: int = 1) -> Resp:
    """
    获取天勍的传感器列表
    :param ignore_related: 是否忽略已建立关联的第三方传感器, 0不忽略, 1忽略
    """
    resp = tianqing_get_device_list(sensor_category, merchant_no, store_no)
    if ignore_related:
        db_session = new_db_session()
        s = select(SensorOrm.sensor_sn).where(
            SensorOrm.sensor_category == sensor_category, 
            SensorOrm.merchant_no == merchant_no,
            SensorOrm.customer_id != None, SensorOrm.store_id != None,
            )
        related_sensors = db_session.execute(s).scalars().all()
    else:
        related_sensors = []
    if resp:
        resp.data = [{
            "value": tianqing_package_raw_sensor_to_standard(sensor_category=sensor_category, 
                                                             merchant_no=merchant_no,
                                                             customer_id=customer_id, 
                                                             store_id=store_id, data=x),
            "name": x['name']
        } for x in resp.data if x['sensorId'] not in related_sensors]
    return resp


def tianqing_get_device_list(sensor_category: str, 
                             merchant_no: str, store_no: str,
                             host_no: str | None = None) -> Resp:
    """
    天勍获取设备列表
    类型:4.电表，2，温控，5.水表，6，燃气表
    测试： merchant_no：jiyoujia  store_no：10001
    'merchantId' = 'jiyoujia'
    'storeId' = '10001'
    host_no: ''KSE0168129' # 工厂编号(主机号)  目前实测这个参数没用
    """
    url = "https://xcx.itianqing.com/scat-api/v1/wms/data/getDeviceList"
    type = "4" if sensor_category == SensorCategory.ELECTRICITY.value else "2"
    params = {
        "type": type,
        "merchantId": merchant_no,
        "storeId": store_no,
        "hostNo": host_no,
        "limit": 100,
        "offset": 0,
        }
    resp = tianqing_send_request(method="get", url=url, params=params)
    return resp


def tianqing_get_device_data(merchant_no: str, host_no: str, sensor_sn: str, sensor_category: str = None) -> Resp:
    """
    获取传感器最新数据
    生产环境一般会使用异步函数，这个一般函数做测试
    :param type: 型:4.电表，2，温控，5.水表，6，燃气表
    :param host_no:  工厂编号(主机号)
    :param sensor_sn: 传感器id
    """
    url = 'https://xcx.itianqing.com/scat-api/v1/wms/data/getDeviceData'
    sensor_category = SensorCategory.ELECTRICITY.value if sensor_category is None else sensor_category
    type: str = "4" if sensor_category == SensorCategory.ELECTRICITY.value else "2"
    params = {
        "type": type,
        "hostNo": host_no,
        "sensorId": sensor_sn,
        "merchantId": merchant_no,
    }
    resp = tianqing_send_request(method="get", url=url, params=params)
    if resp:
        if resp.data:  # 有数据，没有数据5分钟视为离线
            # {'lastTime': '2024-11-06 16:42:48', 'hostNo': '20200501', 'lastData': '6855.25', 'sensorId': '98D8638B6FE0/1AL1'}
            ...
    return resp


def tianqing_get_sensors_from_local() -> List[dict]:
    """
    从本地数据库/缓存获取传感器列表
    :return: _description_
    """
    data = MEM_CACHE.get(TIANQING_SENSORS_CACHE_KEY)
    if data:
        logger.debug(f"从缓存读取了{len(data)}个传感器")
    else:
        db_session = new_db_session()
        s = select(SensorOrm.sensor_category,
                   SensorOrm.merchant_no,
                   SensorOrm.uuid,
                   SensorOrm.sensor_sn,
                   SensorOrm.customer_id,
                   SensorOrm.store_id,
                   ).where(     
                    SensorOrm.manufacturer == ElectricitySensorManufacturer.TIAN_QING.value,  # 上海天勍有温度和电量两种传感器，值都是一样的
                    SensorOrm.merchant_no.is_not(None)
                    )
        names = ["sensor_category", "merchant_no", "host_no", "sensor_sn", "customer_id", "store_id"]
        data = [dict(zip(names, x)) for x in db_session.execute(s).fetchall()]
        db_session.close()
        MEM_CACHE.set(key=TIANQING_SENSORS_CACHE_KEY, value=data, timeout=TIANQING_SENSORS_CACHE_SSL)
        logger.debug(f"从数据库读取了{len(data)}个天勍传感器")
    return data


def tianqing_save_to_db(measurement: str, 
                        bucket_name: str, 
                        tags: dict, fields: dict) -> int:
    """
    把传感器数据写入 influxdb 数据库
    :param measurement: 测量类型
    :param bucket_name: 桶名
    :param tags: 标签
    :param fields:  字段
    """
    status = 0
    point = Point(measurement)
    for k, v in tags.items():
        point.tag(k, v)
    for k, v in fields.items():
        point.field(k, v)
    write_api = INFLUX_CLI.write_api(write_options=SYNCHRONOUS)
    try:
        write_api.write(bucket=bucket_name, org=INFLUXDB_ORG, record=[point])
    except Exception as e:
        status = 1
        logger.error(e)
    finally:
        uuid = tags['uuid']
        group_id = tags['grp']
        nodes = [{"id": tags['id']}]
        InFluxDBAlertOrm.recovery_offline_alert(uuid=uuid, group_id=group_id, nodes=nodes)
        return status


def tianqing_test_global_info():
    """
    测试获取全局信息
    设备数|商户号|门店id|主机No|
    2 ss 10001 KSA3527232
    27 dzsp DZ1001 20200501
    27 dzsp DZ1001 20200501
    2 suntop sun1001 20200720001
    4 yike BL1001 F0FE6B58D405
    3 eleven el1001 98D8635379E4
    8 61ing 61001 202201200001
    6 fmart 202549 KSE0168104
    6 ganso 1001 05100001
        """
    resp = tianqing_get_customers()
    for x in resp.data['records']:
        merchantId = x['merchantId']
        # print(x['merchantName'])
        # if x['merchantName'] == '域禾科技':
        #     continue
        resp2 = tianqing_get_stores(merchantId)
        if len(resp2.data['records']) > 0:
            for store in resp2.data['records']:
                resp3 = tianqing_get_device_list(SensorCategory.TEMPERATURE.value,
                                                 merchantId, 
                                                 store['storeId'],
                                                 )
                if len(resp3.data) > 1:
                    print(x['merchantName'], len(resp3.data), merchantId, store['storeId'], store['hostNo'])
                    for device in resp3.data:
                        # print(device)
                        resp = tianqing_get_device_data(merchantId, store['hostNo'], device['sensorId'])
                        if resp.data:
                            print(f"{x['merchantName']}, {x['merchantId']}, storeName:{store['storeName']},storeId:{store['storeId']}, host_no: {device['hostNo']},sensorName:{device['name']}, sensor_sn:{device['sensorId']} data: {resp.data}")


if __name__ == '__main__':
    tianqing_get_sensors_from_local()
    # tianqing_test_global_info()
    # resp = tianqing_get_device_list('dzsp', 'DZ1001', '20200501')
    # if resp:
    #     for device in resp.data:
    #         print(device)
    # else:
    #     print(resp)
    # 98D8638B6FE0/1AL1
    # 打印设备清单
    merchantId = "yhkj"
    tianqing_get_device_list(SensorCategory.ELECTRICITY.value, merchantId, '1002')
    resp2 = tianqing_get_stores(merchantId)
    if len(resp2.data['records']) > 0:
        for store in resp2.data['records']:
            for sensor_category in [SensorCategory.TEMPERATURE.value, SensorCategory.ELECTRICITY.value]:
                resp3 = tianqing_get_device_list(sensor_category,
                                                merchantId, 
                                                store['storeId'],
                                                # store['hostNo'],
                                                )
                if len(resp3.data) > 1:
                    for device in resp3.data:
                        # print(device)
                        resp = tianqing_get_device_data(merchantId, store['hostNo'], device['sensorId'], sensor_category)
                        print(f"门店no:{store['storeId']} 门店名称:{store['storeName']} 传感器id:{device['sensorId']} 传感器名称: {device['name']} 传感器类型:{sensor_category} 传感器数据: {resp.data}")
 

    resp
    pass